E-이스티오 DNS 프록시 동작
개요
이스티오는 서비스 메시로서 각 서비스는 범위 설정을 하지만 않았다면 서로의 서비스에 통신을 보낼 수 있도록 서로에게 투명해야 한다.
즉, 서비스 디스커버리가 가능해야 한다는 것이다.
서비스 디스커버리는 기본적으로 중앙에서 각 서비스 별 호스트와 상응하는 주소를 테이블로 관리하는 방식으로 이뤄진다.
이를 서비스 레지스트리라고 부르는데, 중앙에서 레지스트리를 구성하고 각 서비스에 해당 정보를 전달해주면 서비스 디스커버리가 가능하게 된다.
구체적으로 이 방법에 대해 알아보자.
기본 서비스 디스커버리 방식
생각해보면 어차피 모든 설정은 이스티오 컨트롤 플레인에서 각 서비스에 주입해준다.
그러니 istiod에서 서비스들이 연결될 때 해당 서비스의 정보를 받아 레지스트리에 등록하면 될 것 같다.
하지만 실상 그렇게 단순하게만 설정이 되지는 않는 게, 각 데이터 플레인의 서비스들은 자신의 주소를 사실 알지 못한다.
생각해보면 당연하다.
- 파드가 띄워진다.
- 이 파드에 사이드카로 pilot-agent와 엔보이가 세팅되고, 이들은 주입받은 신원 정보를 바탕으로 자신의 신원을 구성하며 istiod와 연결된다.
- 그런데 파드의 가상 주소를 제공하는 서비스는 아직 없을 수 있다.
즉, 워크로드로서 데이터 플레인이 컨플에 연결되는 것은 가능하나, 이 워크로드에 네트워크 접근 경로와 설정까지 결합된 서비스로서 기능한다는 것은 한 단계의 차원을 더 요구하는 작업이라는 것이다.
이에 대해서 이스티오의 방식은 사실 간단하다.
어차피 쿠버네티스 클러스터에서 굴러가니까, 쿠버네티스에서 지원하는 디스커버리를 활용하면 된다!
쿠버에서는 서비스 리소스를 통해 실제 파드로의 추상화된 주소를 제공하기 때문에, 이스티오 역시 이것을 서비스 별 주소로 활용한다.
그래서 istiod는 kube-apiserver와 통신하며 서비스와 파드 등의 정보를 가져오고, 이를 기반으로 서비스 레지스트리에 활용될 실제 서비스들의 엔드포인트를 구성한다.
각 프록시는 이 설정 정보를 전달받아 실제 통신 경로를 알 수 있게 된다.
한계
그런데 문제가 생기는 구간이 있다.
쿠버네티스의 서비스 리소스를 기반으로 레지스트리를 구성하기에, 모든 서비스는 쿠버 서비스가 배치돼야 비로소 제대로 인식될 수 있다는 것이다.
구체적으로 어떤 상황에서 문제가 발생하는가?
- 이스티오 서비스엔트리
- 한 파드의 어플리케이션이 서비스 B에 접근하고 싶다고 해보자.
- 이때 서비스 B는 서비스엔트리 리소스를 활용해 등록됐다.
- 사이드카 프록시는 istiod로부터 B의 엔드포인트 정보를 받을 수는 있다.
- 그러나 어플리케이션은 서비스 B의 주소를 알 수가 없다는 것이 문제!
- DNS 질의를 Core DNS에 보내는데 Core DNS는 해당 도메인 이름을 모른다.
- 결국 해당 도메인 질의를 상위 네임서버로 넘기게 되는데 결과적으로 질의가 실패할 수 있다.
- 어플리케이션 단에서 질의가 실패하니 애초에 요청을 보내지도 않게 된다.
- 이스티오 멀티 클러스터 메시
- 외부의 클러스터의 서비스에 접근하는 상황에서도 같은 문제가 발생한다.
- 각 클러스터는 각자 Core DNS를 구성하기 때문이다.
- 가상 머신 통합
- 결국 위와 같은 이야기이다.
- 당연히 가상 머신은 클러스터 내부의 주소를 기본적으로 알 방법이 없다.
대안
서비스 메시로서 같은 서비스 레지스트리의 정보를 바탕으로 한 통신은 당연한 기본 요소이다.
여기에 간단한 방법 중 하나는 바로 스텁 서비스(stub service)를 만드는 것이다.
실제로 이 서비스에 매칭되는 파드는 존재하지 않지만, 아무튼 서비스를 만들기만 하면 클러스터 내부에서는 가상 IP를 받게 되므로 최소한 어플리케이션은 요청을 날릴 수 있게 된다.
요청을 날리면 그때부터는 엔보이가 냉큼 받아 도메인 이름을 기반으로 실제로 트래픽이 가야할 주소로 요청을 날려줄 것이다.
그러나 이 방식을 가상 머신에 대해 적용할 수는 없다는 게 또 문제이다.
가상머신이라 하면 클러스터 환경이 애초에 아니기 때문에 이걸 일일히 가상의 주소를 만드는 것은 어렵다.
그래서, 이러한 DNS 질의 문제, 서비스 디스커버리 문제를 해결하고자 나온 기능이 있으니, 바로 DNS 프록시이다.
DNS 프록시
지금부터는 가상머신에서 활용하는 것에 초점을 맞춰서 설명을 진행한다.
그러나 해당 기능은 비단 가상머신에서만 가능한 건 아니다.
그냥 프록시 설정에 특정 인자를 넣어주면 간단하게 이 기능이 적용되니 말이다.
이스티오 1.8 버전 이전에는 가상머신의 DNS 질의를 위해 External DNS를 활용하는 등의 차선책을 썼다고 한다.
그러나 이후에는 아예 pilot-agent가 DNS 서버로서 역할을 할 수 있는 기능이 추가됐고, 이 기능을 DNS 프록시라고 부른다.[1]
어차피 iptables로 어플리케이션의 트래픽 경로가 변경된다.
그럼 애초에 이럴 거 pilot-agent가 DNS 질의에 대해서도 프록시 기능을 할 수 있게 만들자! 라는 것이 핵심이다.
이 기능을 활성화하면 일단 에이전트는 15053포트로 DNS 질의를 리스닝한다.
그리고 iptables 룰에는 DNS 질의가 15053으로 향하도록 세팅된다.
이를 통해 에이전트는 DNS 기능을 전담하는 프록시 역할을 하게 된다.
istiod에서는 지속적으로 서비스 엔트리 리소스나 서비스 관련 정보들을 토대로 도메인 이름 관련 정보를 조회한다.
그리고 이 정보를 에이전트에게 동기화시키는데, 이 동기화 api을 Name Discovery Service, 줄여서 NDS라 부른다.
(이름을 흉내냈지만 엔보이의 api는 아니다.)
이를 통해 에이전트는 클러스터 관련 질의에 대해 정상적으로 응답해줄 수 있다.
이 기능은 꽤나 유용한데, 캐싱이나 순수 TCP 패킷도 처리 가능하기 때문이다.
동작
그럼 구체적으로 DNS 리졸빙을 하는가?
- 질의가 클러스터의 도메인이다.
- 에이전트는 클러스터 관련 도메인 정보는 전부 istiod로부터 NDS를 통해 전달받아 테이블로 관리한다.
- 그렇기에 해당 주소를 그대로 반환해준다.
- 질의가 클러스터와 관련없는 도메인이다.
- 이 경우 에이전트는 자신도 결국 모르는 주소이고, 결국 원래 질의가 향했어야 할 서버로 다시 질의한다.
- 가상머신에서는 외부 네임서버일 것이고, 클러스터 내부에서는 Core DNS가 될 것이다.
가상머신에서 DNS 프록시 동작 추적
가상머신이 메시에 통합되는 과정 중 큰 축을 담당하는 기능이 바로 DNS 프록시이다.
클러스터의 도메인을 가상머신이 제대로 해석할 수 있도록, pilot-agent는 15053 포트를 열고 DNS 프록시로서 기능한다.
그리고 처음 사이드카 서비스가 기동될 때 iptables가 수정돼 모든 DNS가 해당 포트로 가게 된다.
세팅
세팅은 E-이스티오 가상머신 통합을 참고한다.
iptables-save | grep 'to-ports 15053'
보다시피 127.0.0.53의 53포트로 가는 모든 요청은 15053으로 리다이렉트된다.
참고로 127.0.0.53은 system-resolved라는 우분투 os의 리졸버의 주소이다.
ss -tunlp | grep 127.0.0.53
system-resolved는 실제 외부 네임서버로 질의를 날리기 이전, 캐싱이나 내부 호스트 네임 해석을 제공하는 리졸버 데몬이다.
기본적인 모든 dns 요청은 이놈을 향하는데 iptables로 이걸 프록시로 돌려버린 것이다!
그래서 DNS 프록시로서 에이전트는 어떻게 동작하는가?
외부 도메인에 대해
일단 첫번째로 클러스터의 도메인이 아닌 경우에 대해서는 원래대로 로컬 리졸버에게 질의를 날린다.
간단하게 외부 주소 질의를 날리고 termshark로 확인해보자.
dig +short naver.com
통신의 흐름은 총 4번 추적된다.
한 홉이 있다면 6번이 될 수도 있긴 하다.
아무튼 먼저 내 요청이 에이전트에 전달됐다.
이후 패킷 도둑 에이전트가 자신도 모른다 싶으니 나 몰라라 로컬 리졸버에게 질의를 날려버린다.
이후에는 해당 응답이 돌아오고, 에이전트가 자신이 리졸버인 척 처음 요청에 대한 응답을 반환하는 식으로 구성된다.
그런데 에이전트 스스로의 도메인 질의는 왜 자신에게 돌아가지 않는가?
iptables를 보면 이 답을 확실하게 알 수 있다.
iptables -t nat -L -n -v
에이전트의 UID, GID로 날아가는 패킷에 대해서는 iptables에서 바로 리턴을 하도록 돼있어 관련한 패킷은 엔보이에 들어가지 않게 된다.
그냥 iptables 상에서 본격적으로 조작이 일어나는 체인은 맨 아래 ISTIO_OUTPUT_DNS
, ISTIO_REDIRECT
인데 해당 체인에 들어가기 전에 먼저 GID가 998이면 리턴을 때려버려서 정상적으로 패킷이 처리되는 것이다.
클러스터 도메인에 대해
클러스터 도메인 질의는 위에서 찍은 사진으로 대체한다.
dig +short webapp.istioinaction
날린 요청이 자연스럽게 로컬의 15053 포트로 향하는 모습을 확인할 수 있다.
여기에서는 패킷의 흐름은 두 번에서 끝난다.
즉 에이전트가 해당 도메인에 대해 추가 질의를 하지 않고 그대로 응답을 해버린 것이다.
위 도식에서 나오듯이 에이전트는 istiod로부터 NDS api를 통해 도메인 정보를 전부 가지고 온다.
istiod에서는 이를 디버깅할 수 있도록 엔드포인트를 노출하고 있다.
kubectl -n istio-system exec deploy/istiod -- curl -Ls "localhost:8080/debug/ndsz?proxyID=forum-vm.forum-services" | jq
보다시피 proxyID 별로 적용되는 설정을 조회할 수 있다.
그러면 이렇게 네임테이블이 출력되는데, 이게 에이전트가 받게되는 테이블인 것이다!
여기에는 전부 FQDN 밖에 없는데, 이 정보를 받고 에이전트는 자체적으로 해당 값들을 잘개 쪼개 도메인으로 엔보이에 전달한다.
그래서 엔보이 라우트 쪽 설정을 보면 여러 도메인이 들어있는 것을 확인할 수 있는 것이다.
NDS가 전달되고 있다는 것은 istiod 로그로도 확인할 수 있다.
k -n istio-system logs istiod-848dbb56f6-s86t6 | grep NDS
보다시피 포럼 측은 지속적으로 NDS를 통해 istiod로부터 설정을 받고 있는 것을 확인할 수 있다.
그런데 다른 서비스들은 왜 NDS를 받지 않는가?
중간에 가상머신을 위한 세팅을 하면서 default config를 바꿨던 것을 봤을 것이다.
사실 이건 별 건 아니고 처음 실습 세팅할 때 설정된 값이 그대로 남아있어서 그렇다...
맨 초기 세팅할 때 워크로드들을 배포했고, 이때 주입된 사이드카는 그때 당시 설정을 받았으니 별다른 변경이 발생하지 않은 것이다.
실험삼아 웹앱 양식 파일을 기반으로 워크로드를 지우고 다시 배포했다.
제대로 NDS 설정을 받는 것을 확인할 수 있다.
관련 문서
지식 문서, EXPLAIN
이름9 | is-folder | 생성 일자 |
---|---|---|
E-이스티오 컨트롤 플레인 성능 최적화 | false | 2025-05-18 02:29 |
E-이스티오 메시 스케일링 | false | 2025-06-08 23:41 |
Istio VirtualService | false | 2025-04-21 10:49 |
Istio Traffic Management | true | 2025-04-21 12:01 |
Istio Sidecar | false | 2025-05-13 22:27 |
Istio ServiceEntry | false | 2025-04-17 14:12 |
Istio ProxyConfig | false | 2025-05-17 19:32 |
Istio Gateway | false | 2025-04-16 21:50 |
Istio DestinationRule | false | 2025-04-21 10:50 |
기타 문서
Z0-연관 knowledge, Z1-트러블슈팅 Z2-디자인,설계, Z3-임시, Z5-프로젝트,아카이브, Z8,9-미분류,미완이름9 | 코드 | 타입 | 생성 일자 |
---|---|---|---|
2W - 인그레스 게이트웨이 실습 | Z8 | published | 2025-04-17 22:06 |
3W - 데스티네이션 룰을 활용한 네트워크 복원력 | Z8 | published | 2025-04-26 00:35 |
3W - 타임아웃, 재시도를 활용한 네트워크 복원력 | Z8 | published | 2025-04-26 00:41 |
3W - 버츄얼 서비스를 활용한 기본 트래픽 관리 | Z8 | published | 2025-04-22 21:56 |
3W - 서비스 엔트리와 이그레스 게이트웨이 | Z8 | published | 2025-04-22 22:01 |
3W - 트래픽 가중치 - flagger와 argo rollout을 이용한 점진적 배포 | Z8 | published | 2025-04-22 21:59 |
3W - 트래픽 미러링 패킷 캡쳐 | Z8 | published | 2025-04-22 22:00 |
6W - 이스티오 컨트롤 플레인 성능 최적화 | Z8 | published | 2025-05-18 02:29 |
7W - 이스티오 메시 스케일링 | Z8 | published | 2025-06-09 02:04 |